package system

import (
	"context"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"
	"server/internal/consts"
	"server/internal/dao"
	"server/internal/library/crontab"
	"server/internal/model"
	"server/internal/model/do"
	"server/internal/model/entity"
	"server/internal/service"
)

type sSystemCrontab struct {
}

func init() {
	service.RegisterSystemCrontab(&sSystemCrontab{})
}

func (s *sSystemCrontab) Create(ctx context.Context, in model.CrontabFormInput) (id int64, err error) {
	if err = s.checkCodeIsRepeat(ctx, in.Name, 0); err != nil {
		return
	}
	if !crontab.CheckTaskPatternIsValid(ctx, in.Pattern) {
		err = gerror.New("表达式格式错误")
		return
	}

	data := entity.SystemCrontab{
		CategoryId: uint(in.CategoryId),
		Title:      in.Title,
		Name:       in.Name,
		Params:     in.Params,
		Pattern:    in.Pattern,
		Policy:     in.Policy,
		Count:      in.Count,
		Sort:       in.Sort,
		Status:     in.Status,
		Remark:     in.Remark,
		CreatedBy:  uint64(service.SystemLogin().GetAdminID(ctx)),
	}
	id, err = dao.SystemCrontab.Ctx(ctx).Data(data).InsertAndGetId()

	if err != nil {
		return
	}
	data.Id = uint64(id)

	//启动任务
	if data.Status == consts.CrontabStatusEnabled {
		if err = crontab.StartTask(data); err != nil {
			return
		}
	}

	return
}

func (s *sSystemCrontab) checkCodeIsRepeat(ctx context.Context, name string, id int64) error {
	where := g.Map{
		"name": name,
	}
	if id > 0 {
		where["id <> ?"] = id
	}
	count, err := dao.SystemCrontab.Ctx(ctx).Where(where).Count()
	if err != nil {
		return err
	}
	if count > 0 {
		return gerror.New("配置项 重复")
	}
	return nil
}

func (s *sSystemCrontab) UpdateByID(ctx context.Context, id int64, in model.CrontabFormInput) (affected int64, err error) {
	crontabInfo := new(entity.SystemCrontab)
	err = dao.SystemCrontab.Ctx(ctx).Where(do.SystemCrontab{Id: id}).Scan(crontabInfo)
	if err != nil {
		return
	}
	if !crontab.CheckTaskPatternIsValid(ctx, in.Pattern) {
		err = gerror.New("表达式格式错误")
		return
	}
	if err = s.checkCodeIsRepeat(ctx, in.Name, id); err != nil {
		return
	}
	affected, err = dao.SystemCrontab.Ctx(ctx).Data(do.SystemCrontab{
		CategoryId: in.CategoryId,
		Title:      in.Title,
		Name:       in.Name,
		Params:     in.Params,
		Pattern:    in.Pattern,
		Policy:     in.Policy,
		Count:      in.Count,
		Sort:       in.Sort,
		Status:     in.Status,
		Remark:     in.Remark,
		UpdatedBy:  service.SystemLogin().GetAdminID(ctx),
	}).Where(do.SystemCrontab{Id: id}).UpdateAndGetAffected()
	if err != nil {
		return
	}

	crontab.RefreshTaskStatus(*crontabInfo)

	return
}

func (s *sSystemCrontab) DeleteByID(ctx context.Context, id int64) (affected int64, err error) {
	crontabInfo := new(entity.SystemCrontab)
	err = dao.SystemCrontab.Ctx(ctx).Where(do.SystemCrontab{Id: id}).Scan(crontabInfo)
	if err != nil {
		return
	}
	affected, err = dao.SystemCrontab.Ctx(ctx).Data(do.SystemCrontab{
		DeletedAt: gtime.Now(),
		DeletedBy: service.SystemLogin().GetAdminID(ctx),
	}).Where(do.SystemCrontab{Id: id}).UpdateAndGetAffected()
	if err != nil {
		return
	}
	if affected > 0 {
		crontab.DeleteTask(*crontabInfo)
	}
	return
}

func (s *sSystemCrontab) List(ctx context.Context, in model.CrontabListInput) (configs []model.CrontabOutput, total int, err error) {
	configs = make([]model.CrontabOutput, 0)
	where := g.Map{}
	if len(in.Title) > 0 {
		where["title like ?"] = "%" + in.Title + "%"
	}
	if len(in.Name) > 0 {
		where["name like ?"] = "%" + in.Name + "%"
	}
	if in.CategoryId > 0 {
		where["category_id"] = in.CategoryId
	}
	err = dao.SystemCrontab.Ctx(ctx).Where(where).Page(in.Page, in.PageSize).ScanAndCount(&configs, &total, true)
	if err != nil {
		return
	}
	if total == 0 {
		return
	}

	// 分类信息
	_ = dao.SystemCrontabCategory.Ctx(ctx).As("cate").Fields("cate.*").
		WhereIn("cate.id", gdb.ListItemValuesUnique(configs, "CategoryId")).
		ScanList(&configs, "CategoryInfo", "id:CategoryId")

	// 创建人
	_ = dao.SystemUser.Ctx(ctx).As("u").Fields("u.*").
		WhereIn("u.id", gdb.ListItemValuesUnique(configs, "CreatedBy")).
		ScanList(&configs, "CreatedAdmin", "id:created_by")

	// 更新人
	_ = dao.SystemUser.Ctx(ctx).As("u").Fields("u.*").
		WhereIn("u.id", gdb.ListItemValuesUnique(configs, "UpdatedBy")).
		ScanList(&configs, "UpdatedAdmin", "id:updated_by")

	return
}

func (s *sSystemCrontab) StartAllCrontab(ctx context.Context) (err error) {
	jobs := make([]entity.SystemCrontab, 0)
	err = dao.SystemCrontab.Ctx(ctx).Where(do.SystemCrontab{
		Status: consts.CrontabStatusEnabled,
	}).OrderAsc("sort").Scan(&jobs)
	if err != nil {
		return
	}
	_ = crontab.StartTasks(jobs)
	return nil
}

// GetRegisterCrontabList 获取已注册的定时任务列表
func (s *sSystemCrontab) GetRegisterCrontabList(ctx context.Context) []string {
	return crontab.GetRegisterCrontabList()
}

func (s *sSystemCrontab) CrontabTaskLogs(ctx context.Context, id int64, date string) (err error) {
	job := new(entity.SystemCrontab)
	err = dao.SystemCrontab.Ctx(ctx).Where(do.SystemCrontab{Id: id}).Scan(job)
	if err != nil {
		return
	}

	return
}
